import base64
from django.utils import timezone
import re
from django.conf import settings
from Crypto.Cipher import AES
import requests
from rest_framework import generics, permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from .serializers import UserProfileSerializer,CustomerSerializer, CustomerCreateSerializer, CustomerUpdateSerializer, WeChatLoginSerializer
from .models import User
from rest_framework.pagination import PageNumberPagination
from rest_framework_simplejwt.tokens import RefreshToken
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import get_user_model

import logging


logger = logging.getLogger(__name__)

class UserProfileView(generics.RetrieveUpdateAPIView):
    serializer_class = UserProfileSerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_object(self):
        return self.request.user
    
class UserStatsView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]
    
    def get(self, request):
        user = request.user
        return Response({
            'order_count': user.orders.count(),

            'points': user.points or 0  
        })

class UserAvatarUploadView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]
    
    def post(self, request):
        user = request.user
        if 'avatar' not in request.FILES:
            return Response({'error': 'No avatar provided'}, status=status.HTTP_400_BAD_REQUEST)
        
        user.avatar = request.FILES['avatar']
        user.save()
        return Response({
            'avatar_url': user.avatar.url
        })

class UserLogoutView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]
    
    def post(self, request):
        # 实际应根据您使用的认证系统实现
        request.auth.delete()  # 如果是Token认证
        return Response({'message': 'Logged out successfully'})
    
class UserPhoneView(APIView):
    """
    用户手机号相关视图
    GET /api/user/phone/ - 获取手机号
    POST /api/user/phone/ - 更新手机号
    """
    def get(self, request):
        # 获取手机号逻辑
        return Response({"phone": request.user.phone})
    
    def post(self, request):
        # 更新手机号逻辑
        phone = request.data.get('phone')
        if phone:
            request.user.phone = phone
            request.user.save()
            return Response({"status": "success"})
        return Response({"error": "手机号不能为空"}, status=400)
    
# views.py
# 假设这是验证验证码的函数
def verify_phone_code(phone, verification_code):
    # 这里可以实现具体的验证码验证逻辑
    # 例如从缓存中获取验证码并比较
    return True

User = get_user_model()

from datetime import timezone
from rest_framework import status, permissions
from rest_framework.views import APIView
from django.utils import timezone
from .models import User

logger = logging.getLogger(__name__)

from rest_framework import status, permissions
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from django.utils import timezone
from .models import User



class WeChatLoginView(APIView):
    permission_classes = [permissions.AllowAny]
    
    def post(self, request):
        # 1. 验证微信配置
        try:
            wechat_config = settings.WECHAT_CONFIG['consumer']
            app_id = wechat_config['appid']
            secret = wechat_config['secret']
        except (KeyError, AttributeError) as e:
            logger.error(f"WeChat config error: {str(e)}")
            return Response(
                {"detail": "Server configuration error"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        
        # 2. 验证请求数据
        serializer = WeChatLoginSerializer(data=request.data)
        if not serializer.is_valid():
            logger.warning(f"Validation failed: {serializer.errors}")
            return Response(
                {"detail": "Invalid login data", "errors": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            # 3. 获取微信openid和session_key
            code = serializer.validated_data['code']
            wechat_data = self._get_wechat_session(code, app_id, secret)
            openid = wechat_data.get('openid')
            session_key = wechat_data.get('session_key')
            
            if not openid or not session_key:
                return Response(
                    {"detail": "Failed to get WeChat openid or session_key"},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            # 4. 解密手机号 - 使用通用解密方法
            phone_number = None
            encrypted_data = serializer.validated_data.get('encryptedData')
            iv = serializer.validated_data.get('iv')
            
            if encrypted_data and iv and session_key:
                decrypted_data = self._decrypt_data(encrypted_data, iv, session_key, app_id)
                if decrypted_data and 'phoneNumber' in decrypted_data:
                    phone_number = decrypted_data['phoneNumber']
                    logger.info(f"Successfully decrypted phone number")
            
            # 5. 查找或创建用户
            user, created = self._get_or_create_user(openid)
            
            # 6. 更新用户信息
            user_info = serializer.validated_data.get('user_info', {})
            city = serializer.validated_data.get('city')
            self._update_user_profile(user, user_info, phone_number, city)
            
            # 7. 更新登录时间
            user.last_login = timezone.now()
            user.save(update_fields=['last_login'])
            
            # 8. 生成JWT Token并构建响应
            refresh = RefreshToken.for_user(user)
            response_data = self._build_response_data(user, refresh, created, openid)
            
            logger.info(f"User {user.id} (openid: {openid}) logged in successfully")
            return Response(response_data, status=status.HTTP_200_OK)
            
        except Exception as e:
            logger.error(f"Login processing error: {str(e)}", exc_info=True)
            return Response(
                {"detail": "Login processing failed"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _decrypt_data(self, encrypted_data, iv, session_key, appid):
        """
        通用微信数据解密方法
        参考微信官方解密算法实现，不依赖特定类库
        """
        try:
            # 对session_key、encrypted_data、iv进行Base64解码
            session_key = base64.b64decode(session_key)
            encrypted_data = base64.b64decode(encrypted_data)
            iv = base64.b64decode(iv)
            
            # 使用AES-CBC模式解密
            cipher = AES.new(session_key, AES.MODE_CBC, iv)
            decrypted = cipher.decrypt(encrypted_data)
            
            # 去除PKCS#7填充
            unpad = lambda s: s[:-ord(s[len(s)-1:])]
            decrypted_str = unpad(decrypted)
            
            # 解密后的数据为JSON字符串，解析为字典
            import json
            decrypted_data = json.loads(decrypted_str)
            
            # 验证解密数据的appid是否正确
            if decrypted_data.get('watermark', {}).get('appid') != appid:
                logger.error("Decrypted data appid mismatch")
                return None
                
            return decrypted_data
            
        except Exception as e:
            logger.error(f"Data decryption failed: {str(e)}", exc_info=True)
            return None
    
    # 其他方法保持不变...
    def _get_wechat_session(self, code, appid, secret):
        url = (f"https://api.weixin.qq.com/sns/jscode2session?"
               f"appid={appid}&secret={secret}&js_code={code}&grant_type=authorization_code")
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            data = response.json()
            
            if data.get('errcode'):
                logger.error(f"WeChat API error: {data.get('errmsg')} (code: {data.get('errcode')})")
                return {}
            return data
        except requests.exceptions.RequestException as e:
            logger.error(f"Failed to get wechat session: {str(e)}")
            return {}
    
    def _get_or_create_user(self, openid):
        user = User.objects.filter(openid=openid).first()
        if user:
            return user, False
        
        username = self._generate_unique_username(openid)
        user = User.objects.create_user(
            username=username,
            openid=openid,
            password=None,
            last_login=timezone.now()
        )
        return user, True
    
    def _update_user_profile(self, user, user_info, phone_number, city):
        update_fields = []
        
        if 'nickName' in user_info:
            valid_nickname = self._validate_nickname(user_info['nickName'])
            if valid_nickname and valid_nickname != user.nickname:
                user.nickname = valid_nickname
                update_fields.append('nickname')
        
        if 'avatarUrl' in user_info:
            avatar_url = user_info['avatarUrl']
            if avatar_url and avatar_url != user.avatar:
                user.avatar = avatar_url
                update_fields.append('avatar')
        
        if phone_number and phone_number != user.phone:
            user.phone = phone_number
            update_fields.append('phone')
        
        if city and city != user.city:
            user.city = city
            update_fields.append('city')
        
        if update_fields:
            user.save(update_fields=update_fields)
    
    def _generate_unique_username(self, openid):
        return f"wx_{openid[-6:]}"
    
    def _validate_nickname(self, nickname):
        if not nickname:
            return None
            
        valid_chars = re.compile(r'[^a-zA-Z0-9_\u4e00-\u9fa5\s]')
        cleaned_nickname = valid_chars.sub('_', nickname).strip()
        
        if not cleaned_nickname:
            return f"user_{hash(nickname) % 1000000}"
            
        return cleaned_nickname[:30]
    
    def _get_avatar_url(self, user):
        return user.avatar or settings.DEFAULT_AVATAR_URL
    
    def _build_response_data(self, user, refresh, is_new_user, openid):
        access_token = str(refresh.access_token)
        return {
            'user_id': user.id,
            'openid': openid,
            'is_new_user': is_new_user,
            'access': access_token,
            'refresh': str(refresh),
            'token_type': 'Bearer',
            'expires_in': int(refresh.access_token.lifetime.total_seconds()),
            'nickname': user.nickname or f"微信用户{openid[-4:]}",
            'avatar': self._get_avatar_url(user),
            'city': user.city,
            'is_phone_bound': bool(user.phone),
        }

    
class BindPhoneView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            phone = request.data.get('phone')
            code = request.data.get('code')
            
            if not all([phone, code]):
                return Response(
                    {"error": "手机号和验证码不能为空"},
                    status=status.HTTP_400_BAD_REQUEST
                )
                
            # 验证手机号格式
            if not re.match(r'^1[3-9]\d{9}$', phone):
                return Response(
                    {"error": "手机号格式不正确"},
                    status=status.HTTP_400_BAD_REQUEST
                )
                
            # 验证码校验逻辑
            if not verify_phone_code(phone, code):
                return Response(
                    {"error": "验证码错误或已过期"},
                    status=status.HTTP_400_BAD_REQUEST
                )
                
            # 检查手机号是否已被绑定
            if User.objects.filter(phone=phone).exclude(id=request.user.id).exists():
                return Response(
                    {"error": "该手机号已被其他账号使用"},
                    status=status.HTTP_400_BAD_REQUEST
                )
                
            request.user.phone = phone
            request.user.save()
            
            return Response({
                "status": "success",
                "phone": phone
            })
            
        except Exception as e:
            logger.error(f"绑定手机号失败: {str(e)}")
            return Response(
                {"error": "绑定失败，请稍后重试"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    
class CustomerListView(generics.ListAPIView):
    queryset = User.objects.filter(user_type='consumer')
    serializer_class = CustomerSerializer
    permission_classes = [IsAdminUser]
    pagination_class = PageNumberPagination

    def get_queryset(self):
        queryset = super().get_queryset()
        phone = self.request.query_params.get('phone')
        username = self.request.query_params.get('username')
        is_verified = self.request.query_params.get('is_verified')
        
        if phone:
            queryset = queryset.filter(phone__icontains=phone)
        if username:
            queryset = queryset.filter(username__icontains=username)
        if is_verified:
            queryset = queryset.filter(is_verified=is_verified.lower() == 'true')
        return queryset

class CustomerCreateView(generics.CreateAPIView):
    queryset = User.objects.all()
    serializer_class = CustomerCreateSerializer
    permission_classes = [IsAdminUser]

    def perform_create(self, serializer):
        serializer.save(user_type='consumer')

class CustomerDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = User.objects.filter(user_type='consumer')
    serializer_class = CustomerUpdateSerializer
    permission_classes = [IsAdminUser]